﻿using K9Nano.Exceptions;

namespace K9Nano.Settings;

public interface ISettingManager
{
    /// <summary>
    /// Get setting value for Current user
    /// </summary>
    /// <param name="name"></param>
    /// <returns></returns>
    Task<string?> GetSettingValueAsync(string name, CancellationToken cancellation = default);

    /// <summary>
    /// Get setting value for specific user
    /// </summary>
    /// <param name="name"></param>
    /// <param name="userId"></param>
    /// <returns></returns>
    Task<string?> GetSettingValueAsync(string name, long? userId, CancellationToken cancellation = default);

    /// <summary>
    /// Change setting value for Current user
    /// </summary>
    /// <param name="name"></param>
    /// <param name="value"></param>
    /// <returns></returns>
    Task ChangeSettingAsync(string name, string value, CancellationToken cancellation = default);

    /// <summary>
    /// Change setting value for specific user
    /// </summary>
    /// <param name="name"></param>
    /// <param name="value"></param>
    /// <param name="userId"></param>
    /// <returns></returns>
    Task ChangeSettingAsync(string name, string value, long? userId, CancellationToken cancellation = default);

    /// <summary>
    /// Change setting value for specific user
    /// </summary>
    /// <param name="name"></param>
    /// <param name="value"></param>
    /// <param name="userId"></param>
    /// <returns></returns>
    Task ChangeSettingJsonAsync(string name, object value, long? userId, CancellationToken cancellation = default);

    /// <summary>
    /// Change setting value for Current user
    /// </summary>
    /// <param name="name"></param>
    /// <param name="value"></param>
    /// <returns></returns>
    Task ChangeSettingJsonAsync(string name, object value, CancellationToken cancellation = default);

    public Task<string?> GetSettingValueForApplicationAsync(string name, CancellationToken cancellation = default)
    {
        return GetSettingValueAsync(name, default, default);
    }

    public Task ChangeSettingForApplicationAsync(string name, string value, CancellationToken cancellation = default)
    {
        return ChangeSettingAsync(name, value, default, cancellation);
    }

    public Task ChangeSettingForUserAsync(string name, string value, long userId, CancellationToken cancellation = default)
    {
        return ChangeSettingAsync(name, value, userId, cancellation);
    }

    /// <summary>
    /// Get setting value of current user
    /// </summary>
    /// <param name="name"></param>
    /// <returns></returns>
    public async Task<int> GetIntAsync(string name, CancellationToken cancellation = default)
    {
        var value = await GetSettingValueAsync(name, cancellation);
        if (int.TryParse(value, out var i))
        {
            return i;
        }
        throw new FriendlyException($"Can not parse value ({value}) of setting ({name}) to int");
    }

    /// <summary>
    /// Get setting value of specific user
    /// </summary>
    /// <param name="name"></param>
    /// <param name="userId"></param>
    /// <returns></returns>
    public async Task<int> GetIntAsync(string name, long userId, CancellationToken cancellation = default)
    {
        var value = await GetSettingValueAsync(name, userId, cancellation);
        if (int.TryParse(value, out var i))
        {
            return i;
        }
        throw new FriendlyException($"Can not parse value ({value}) of setting ({name}) to int");
    }

    /// <summary>
    /// Get setting value of application
    /// </summary>
    /// <param name="name"></param>
    /// <returns></returns>
    public async Task<int> GetIntForApplicationAsync(string name, CancellationToken cancellation = default)
    {
        var value = await GetSettingValueAsync(name, default, cancellation);
        if (int.TryParse(value, out var i))
        {
            return i;
        }
        throw new FriendlyException($"Can not parse value ({value}) of setting ({name}) to int");
    }

    /// <summary>
    /// Get setting value of current user
    /// </summary>
    /// <param name="name"></param>
    /// <returns></returns>
    public async Task<long> GetLongAsync(string name, CancellationToken cancellation = default)
    {
        var value = await GetSettingValueAsync(name, cancellation);
        if (long.TryParse(value, out var i))
        {
            return i;
        }
        throw new FriendlyException($"Can not parse value ({value}) of setting ({name}) to long");
    }

    /// <summary>
    /// Get setting value of specific user
    /// </summary>
    /// <param name="name"></param>
    /// <param name="userId"></param>
    /// <returns></returns>
    public async Task<long> GetLongAsync(string name, long userId, CancellationToken cancellation = default)
    {
        var value = await GetSettingValueAsync(name, userId, cancellation);
        if (long.TryParse(value, out var i))
        {
            return i;
        }
        throw new FriendlyException($"Can not parse value ({value}) of setting ({name}) to long");
    }

    /// <summary>
    /// Get setting value of application
    /// </summary>
    /// <param name="name"></param>
    /// <returns></returns>
    public async Task<long> GetLongForApplicationAsync(string name, CancellationToken cancellation = default)
    {
        var value = await GetSettingValueAsync(name, default, cancellation);
        if (long.TryParse(value, out var i))
        {
            return i;
        }
        throw new FriendlyException($"Can not parse value ({value}) of setting ({name}) to long");
    }

    /// <summary>
    /// Get setting value of current user
    /// </summary>
    public async Task<bool> GetBooleanAsync(string name, CancellationToken cancellation = default)
    {
        var value = await GetSettingValueAsync(name, cancellation);
        if (bool.TryParse(value, out var i))
        {
            return i;
        }
        throw new FriendlyException($"Can not parse value ({value}) of setting ({name}) to boolean");
    }

    /// <summary>
    /// Get setting value of specific user
    /// </summary>
    public async Task<bool> GetBooleanAsync(string name, long userId, CancellationToken cancellation = default)
    {
        var value = await GetSettingValueAsync(name, userId, cancellation);
        if (bool.TryParse(value, out var i))
        {
            return i;
        }
        throw new FriendlyException($"Can not parse value ({value}) of setting ({name}) to boolean");
    }

    /// <summary>
    /// Get setting value of specific user
    /// </summary>
    public async Task<bool> GetBooleanForApplicationAsync(string name, CancellationToken cancellation = default)
    {
        var value = await GetSettingValueAsync(name, default, cancellation);
        if (bool.TryParse(value, out var i))
        {
            return i;
        }
        throw new FriendlyException($"Can not parse value ({value}) of setting ({name}) to boolean");
    }

    /// <summary>
    /// Get setting value of current user
    /// </summary>
    public async Task<TEnum> GetEnumAsync<TEnum>(string name, CancellationToken cancellation = default) where TEnum : struct, Enum
    {
        var value = await GetSettingValueAsync(name, cancellation);
        if (Enum.TryParse<TEnum>(value, out var i))
        {
            return i;
        }
        throw new FriendlyException($"Can not parse value ({value}) of setting ({name}) to {typeof(TEnum)}");
    }

    /// <summary>
    /// Get setting value of specific user
    /// </summary>
    public async Task<TEnum> GetEnumAsync<TEnum>(string name, long userId, CancellationToken cancellation = default) where TEnum : struct, Enum
    {
        var value = await GetSettingValueAsync(name, userId, cancellation);
        if (Enum.TryParse<TEnum>(value, out var i))
        {
            return i;
        }
        throw new FriendlyException($"Can not parse value ({value}) of setting ({name}) to {typeof(TEnum)}");
    }

    /// <summary>
    /// Get setting value of application
    /// </summary>
    public async Task<TEnum> GetEnumForApplicationAsync<TEnum>(string name, CancellationToken cancellation = default) where TEnum : struct, Enum
    {
        var value = await GetSettingValueAsync(name, default, cancellation);
        if (Enum.TryParse<TEnum>(value, out var i))
        {
            return i;
        }
        throw new FriendlyException($"Can not parse value ({value}) of setting ({name}) to {typeof(TEnum)}");
    }

    /// <summary>
    /// Get setting value of current user
    /// </summary>
    Task<T?> GetJsonAsync<T>(string name, CancellationToken cancellation = default);

    /// <summary>
    /// Get setting value of specific user
    /// </summary>
    Task<T?> GetJsonAsync<T>(string name, long? userId, CancellationToken cancellation = default);

    /// <summary>
    /// Get setting value of application
    /// </summary>
    Task<T?> GetJsonForApplicationAsync<T>(string name, CancellationToken cancellation = default)
        => GetJsonAsync<T>(name, default, cancellation);
}
